﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.UI.Properties;
using SoftwareConsulting.BI11.NumericalMethods;
using SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.Extensions;
using SoftwareConsulting.BI11.Controls.MicrosoftBugsFixes;

namespace SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.ClassificationProblems
{
    public partial class ClassificationProblemWithTrainingManualTrainingDialog : RestorableForm
    {
        private IClassificationProblemWithTraining _problem; //задача классификации с обучением
        private ObjectManualInputArgs _args; //аргументы, которые вернем        
        private bool _bygroups; //флаг расположения признаков по группам
        private ToolStripItem _arrangeByGroupsOrIndicatorPositionItem; //пункт расположения признаков по группам или по положению в показателе

        /// <summary>
        /// Инициализирует диалог
        /// </summary>
        private void Initialize()
        {
            this.SetObjectViewerCaption(Text, (_problem.TrainingCacheCount + 1).ToString());
            var rows = ManualTrainingGrid.Rows;
            rows.Clear();
            var classes = _problem.ClassesNames;
            var attributes = _problem.AttributesNames;
            if ((classes == null) || (attributes == null)
                || (attributes.GetIndicatorValuesCount() == 1) || (classes.GetIndicatorValuesCount() == 1))//1, т.к. 0й - [не важно]
            {
                OKButton.Enabled = false;
                return;
            }
            for (int i = 1; i < attributes.GetIndicatorValuesCount(); i++)//с первого, т.к. 0й - [не важно]
            {
                int attributeIndex = i - 1;
                rows.Add();
                var row = rows[attributeIndex];
                var cells = row.Cells;
                string attributeName = attributes.GetIndicatorValueByPosition(i).Value as string;
                (cells[0] as DataGridViewTextBoxCell).Value = attributeName;
                (cells[1] as DataGridViewTextBoxCell).Value = string.Empty;                
            }
            var classItems = ManualTrainingClassBox.Properties.Items;
            classItems.Clear();
            for (int i = 1; i < classes.GetIndicatorValuesCount(); i++)//с первого, т.к. 0й - [не важно]
            {                
                classItems.Add(classes.GetIndicatorValueByPosition(i).Value as string);
            }
            ManualTrainingClassBox.SelectedIndex = 0;
            _bygroups = false;
            if (_problem.Method == ClassificationProblemMethod.SimpleClassificator)
            {
                var items = ManualTrainingGrid.ContextMenuStrip.Items;
                //var separator = new ToolStripSeparator();
                //items.Add(separator);
                items.Add(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTESBYGROUPS);
                _arrangeByGroupsOrIndicatorPositionItem = items[items.Count - 1];
                _arrangeByGroupsOrIndicatorPositionItem.Click += new EventHandler(AttributesByGroups_Click);
            }
        }

        /// <summary>
        /// Располагает признаки по группам или по положению в показателе
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void AttributesByGroups_Click(object sender, EventArgs args)
        {
            _bygroups = !_bygroups;
            var rows = ManualTrainingGrid.Rows;
            List<AttributeInfo> infos = _problem.GetAttributesInfoSortedByGroups();
            bool[] excluded = new bool[infos.Count];
            for (int i = 0; i < infos.Count; i++)
            {
                var info = infos[i];
                int realPosition = _bygroups ? info.PositionInIndicator : i;
                int needPosition = _bygroups ? i : info.PositionInIndicator;
                var row = rows[realPosition];
                var group = info.Group;
                if (excluded[realPosition])//эту пару исключили из рассмотрения уже ранее в данном цикле                
                {
                    row = rows[needPosition];
                    group = info.Group;
                    group = ClassificationProblemGroupsProcessor.CorrectGroup(group);
                    row.DefaultCellStyle.BackColor = _bygroups ?
                        ClassificationProblemGroupsProcessor.Colors[group] :
                        SystemColors.Window;
                    continue;
                }
                group = ClassificationProblemGroupsProcessor.CorrectGroup(group);
                row.DefaultCellStyle.BackColor = _bygroups ?
                    ClassificationProblemGroupsProcessor.Colors[group] :
                    SystemColors.Window;
                if (realPosition != needPosition)
                {
                    excluded[needPosition] = true;//больше эту пару рассматривать не надо
                    if ((realPosition == (infos.Count - 1))
                        || (needPosition == (infos.Count - 1)))
                    {
                        if (needPosition == (infos.Count - 1))
                        {
                            int temp = needPosition;
                            needPosition = realPosition;
                            realPosition = temp;
                        }
                        rows.AddCopy(needPosition, true);
                        rows.InsertCopy(realPosition, needPosition + 1, true);
                        rows.RemoveAt(needPosition);
                        rows.RemoveAt(realPosition);
                    }
                    else
                    {
                        if (needPosition > realPosition)
                        {
                            int temp = needPosition;
                            needPosition = realPosition;
                            realPosition = temp;
                        }
                        rows.InsertCopy(needPosition, realPosition + 1, true);
                        rows.InsertCopy(realPosition, needPosition + 1, true);
                        rows.RemoveAt(needPosition);
                        rows.RemoveAt(realPosition);
                    }
                }
            }
            _arrangeByGroupsOrIndicatorPositionItem.Text = _bygroups ?
                Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTESBYINDICATORPOSITION :
                Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTESBYGROUPS;
        }

        /// <summary>
        /// Применяет изменения и закрывает диалог
        /// </summary>
        private void ApplyAndClose()
        {            
            var rows = ManualTrainingGrid.Rows;
            var attributes = _problem.AttributesNames;
            double[] values = new double[rows.Count];
            for (int i = 0; i < rows.Count; i++)
            {
                var row = rows[i];
                var cells = row.Cells;
                string valStr = (cells[1] as DataGridViewTextBoxCell).Value as string;
                double val = Constants.NullDouble;
                bool parsed = string.IsNullOrEmpty(valStr) || string.IsNullOrEmpty(valStr.Trim()) 
                    || double.TryParse(valStr, NumberStyles.Float, CultureInfo.CurrentUICulture, out val);
                if (!parsed)
                {
                    GeneralMethods.ShowUserError(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTE_INCORRECTVALUE);
                    cells[1].Selected = true;
                    ManualTrainingGrid.CurrentCell = cells[1];
                    ManualTrainingGrid.BeginEdit(true);
                    DialogResult = DialogResult.None;
                    return;
                }
                values[i] = val;
            }
            double[] result = new double[values.Length];
            values.CopyTo(result, 0);
            if (_bygroups)
            {
                List<AttributeInfo> infos = _problem.GetAttributesInfoSortedByGroups();
                for (int i = 0; i < infos.Count; i++)
                {
                    int realPosition = i;
                    int needPosition = infos[i].PositionInIndicator;
                    result[needPosition] = values[realPosition];
                }
            }
            _args.ObjectInfo = new ClassificationObjectInfo(string.Empty, result, ManualTrainingClassBox.SelectedIndex);
            DialogResult = DialogResult.OK;
            Close();
        }

        /// <summary>
        /// Отменяет изменения и закрывает диалог
        /// </summary>
        private void CancelAndClose()
        {
            DialogResult = DialogResult.Cancel;
            Close();
        }

        public ClassificationProblemWithTrainingManualTrainingDialog(IClassificationProblemWithTraining problem, ObjectManualInputArgs args)
        {
            _problem = problem;
            _args = args;
            InitializeComponent();
        }

        private void OKButton_Click(object sender, EventArgs e)
        {
            ApplyAndClose();
        }

        private void CancelManualTrainingButton_Click(object sender, EventArgs e)
        {
            CancelAndClose();
        }

        private void ClassificationProblemWithTrainingManualTrainingDialog_Load(object sender, EventArgs e)
        {
            Initialize();
        }

        private void FullTrainingButton_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Retry;
            Close();            
        }        
    }
}
